
`include "defines.v"

//----------------------------------------------------------------
//Module Name : csr_reg.v
//Description of module:
// 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/08/31  
//----------------------------------------------------------------


module	csr_reg(
		input	clk,
		input	rst,
		//csr_unit -> csr_reg
		input	[11:0]	csr_addr,				//csr索引地址
		input	csr_w_ena,
		input	csr_r_ena,
		
		input	csr_r_ena_unit,
		input	[11:0]	csr_addr_unit,
		
		input	[`REG_DATA_LEN-1:0] csr_w_data,
		input	ecall_w_en,
		input	mret_w_en,
		input	[`INST_ADDR_LEN-1:0]	pc,
		
		input	[`INST_ADDR_LEN-1:0]	if_addr,
		
		input	time_overstep,				//mtime ≥ mtimecmp,mip的MTIP位置1
		input	time_intr_r,				//中断响应
		
		output	[`REG_DATA_LEN-1:0]	csr_r_data,
		
		output	[`REG_DATA_LEN-1:0]	csr_r_data_unit,
		output	[63:0] mtvec_o,
		output	[63:0] mepc_o,
		output	MTIP_o
		);
		
reg		time_intr_r_r;
always @(posedge clk)
	time_intr_r_r <= time_intr_r;
	
wire	time_intr_en;
assign	time_intr_en = time_intr_r & (~time_intr_r_r);			//后期需要去掉time_intr_diff，直接在时钟上升沿检测time_intr_en
wire	time_intr_diff;
assign	time_intr_diff = time_intr_en & clk;

///////////////////////////////////////mcycle-write//////////////////////////////////////////
reg		[63:0]	mcycle;
wire	mcycle_sel;
wire	mcycle_w_ena;				//mcycle 寄存器写使能,可读可写
wire	mcycle_r_ena;
assign	mcycle_sel = (csr_addr == 12'hb00);						
assign	mcycle_w_ena = mcycle_sel && csr_w_ena;	
assign	mcycle_r_ena = mcycle_sel && csr_r_ena;

wire	mcycle_sel_unit;
assign	mcycle_sel_unit = (csr_addr_unit == 12'hb00);
wire	mcycle_r_ena_unit;
assign	mcycle_r_ena_unit = mcycle_sel_unit && csr_r_ena_unit;

always @(posedge clk or posedge rst)	begin
	if(rst)
		mcycle <= 64'd0;
	else if(mcycle_w_ena)
		mcycle <= csr_w_data;
	else
		mcycle <= mcycle + 1'b1;
end
/////////////////////////////////////////////////////////////////////////////////////////////////////  

//////////////////////////////////////mtvec-write/////////////////////////////////////////////////
reg		[63:0]	mtvec;		//存了异常入口地址，可读可写
wire	mtvec_sel;
wire	mtvec_w_ena;
wire	mtvec_r_ena;
assign	mtvec_sel = (csr_addr == 12'h305);
assign	mtvec_w_ena = mtvec_sel && csr_w_ena;
assign	mtvec_r_ena = mtvec_sel && csr_r_ena;

wire	mtvec_sel_unit;
assign	mtvec_sel_unit = (csr_addr_unit == 12'h305);
wire	mtvec_r_ena_unit;
assign	mtvec_r_ena_unit = mtvec_sel_unit && csr_r_ena_unit;

always @(posedge clk or posedge rst)	begin
	if(rst)
		mtvec <= 64'd0;
	else if(mtvec_w_ena)
		mtvec[63:2] <= csr_w_data[63:2];

end
assign	mtvec_o = mtvec;

///////////////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////mepc-write////////////////////////////////////////////////////////
reg		[63:0]	mepc;				//存储中断或异常时的指令地址，可读可写
wire	mepc_sel;
wire	mepc_w_ena;
wire	mepc_r_ena;
assign	mepc_sel = (csr_addr == 12'h341);
assign	mepc_w_ena = mepc_sel && csr_w_ena;
assign	mepc_r_ena = mepc_sel && csr_r_ena;

wire	mepc_sel_unit;
assign	mepc_sel_unit = (csr_addr_unit == 12'h341);
wire	mepc_r_ena_unit;
assign	mepc_r_ena_unit = mepc_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst or posedge time_intr_diff)	begin
	if(rst)
		mepc <= 64'd0;
	else if(mepc_w_ena)
		mepc <= csr_w_data;
	else if(ecall_w_en)			//异常
		mepc <= pc;
	else if(time_intr_diff)				//中断
		mepc <= if_addr;
end
assign	mepc_o = mepc;

//////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////mcause-write////////////////////////////////////////////////////////
reg		[63:0]	mcause;				//跟踪并控制处理器的当前运行状态
wire	mcause_sel;
wire	mcause_w_ena;
wire	mcause_r_ena;
assign	mcause_sel = (csr_addr == 12'h342);
assign	mcause_w_ena = mcause_sel && csr_w_ena;
assign	mcause_r_ena = mcause_sel && csr_r_ena;

wire	mcause_sel_unit;
assign	mcause_sel_unit = (csr_addr_unit == 12'h342);
wire	mcause_r_ena_unit;
assign	mcause_r_ena_unit = mcause_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst or posedge time_intr_diff)	begin
	if(rst)
		mcause <= 64'd0;
	else if(mcause_w_ena)
		mcause <= csr_w_data;
	else if(ecall_w_en)				
		mcause <= 64'd11;		//环境调用异常
	else if(time_intr_diff)
		mcause <= 64'h8000_0000_0000_0007;			//计时器中断
end

/////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////mstatus-write//////////////////////////////////////////////
reg		[62:0]	mstatus_w;
wire	mstatus_sel;
wire	mstatus_w_ena;
wire	mstatus_r_ena;
assign	mstatus_sel = (csr_addr == 12'h300);
assign	mstatus_w_ena = mstatus_sel && csr_w_ena;
assign	mstatus_r_ena = mstatus_sel && csr_r_ena;

wire	mstatus_sel_unit;
assign	mstatus_sel_unit = (csr_addr_unit == 12'h300);
wire	mstatus_r_ena_unit;
assign	mstatus_r_ena_unit = mstatus_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst or posedge time_intr_diff)	begin
	if(rst)
		mstatus_w <= 63'h0000_0000_0000_1808;
	else if(mstatus_w_ena)	begin
//		mstatus_w[7] <= csr_w_data[7];
//		mstatus_w[3] <= csr_w_data[3];
		mstatus_w <= csr_w_data[62:0];
	end
	else if(ecall_w_en)	begin
		mstatus_w[7] <= mstatus_w[3];
		mstatus_w[3] <= 1'b0;
//		mstatus_w[12:11] <= 2'b11;
	end
	else if(mret_w_en)	begin
		mstatus_w[3] <= mstatus_w[7];
		mstatus_w[7] <= 1'b1;
//		mstatus_w[12:11] <= 2'b00;
	end
	else if(time_intr_diff)	begin
		mstatus_w[7] <= mstatus_w[3];
		mstatus_w[3] <= 1'b0;
//		mstatus_w[12:11] <= 2'b11;
	end

end

wire	mstatus_SD;
assign	mstatus_SD = (mstatus_w[14] & mstatus_w[13]) | (mstatus_w[16] & mstatus_w[15]);
wire	[63:0] mstatus = {mstatus_SD,mstatus_w};

///////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////mip-write////////////////////////////////////////////////////
reg		[63:0]	mip;		//包含等待中断的信息
wire	mip_sel;
wire	mip_w_ena;
wire	mip_r_ena;
assign	mip_sel = (csr_addr == 12'h344);
assign	mip_w_ena = mip_sel && csr_w_ena;
assign	mip_r_ena = mip_sel && csr_r_ena;

wire	mip_sel_unit;
assign	mip_sel_unit = (csr_addr_unit == 12'h344);
wire	mip_r_ena_unit;
assign	mip_r_ena_unit = mip_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst)	begin
	if(rst)
		mip <= 64'd0;
	else if(mip_w_ena)
		mip <= csr_w_data;
	else
		mip[7] <= (time_overstep & mstatus[3] & mie[7]) ? 1'b1 : 1'b0;	
end
assign	MTIP_o = mip[7];

///////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////mie-write////////////////////////////////////////////////////////
reg		[63:0]	mie;
wire	mie_sel;
wire	mie_w_ena;
wire	mie_r_ena;
assign	mie_sel = (csr_addr == 12'h304);
assign	mie_w_ena = mie_sel && csr_w_ena;
assign	mie_r_ena = mie_sel && csr_r_ena;

wire	mie_sel_unit;
assign	mie_sel_unit = (csr_addr_unit == 12'h304);
wire	mie_r_ena_unit;
assign	mie_r_ena_unit = mie_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst)	begin
	if(rst)
		mie <= 64'd0;
	else if(mie_w_ena)
		mie <= csr_w_data;

end
////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////mscratch-write//////////////////////////////////////////////
reg		[63:0]	mscratch;
wire	mscratch_sel;
wire	mscratch_w_ena;
wire	mscratch_r_ena;
assign	mscratch_sel = (csr_addr == 12'h340);
assign	mscratch_w_ena = mscratch_sel && csr_w_ena;
assign	mscratch_r_ena = mscratch_sel && csr_r_ena;

wire	mscratch_sel_unit;
assign	mscratch_sel_unit = (csr_addr_unit == 12'h340);
wire	mscratch_r_ena_unit;
assign	mscratch_r_ena_unit = mscratch_sel_unit && csr_r_ena_unit;
always @(posedge clk or posedge rst)	begin
	if(rst)
		mscratch <= 64'd0;
	else if(mscratch_w_ena)
		mscratch <= csr_w_data;
end
///////////////////////////////////////////////////////////////////////////////////////////////////



assign	csr_r_data = ({64{mcycle_r_ena}} & mcycle)
					| ({64{mtvec_r_ena}} & mtvec)
					| ({64{mepc_r_ena}} & mepc)
					| ({64{mcause_r_ena}} & mcause)
					| ({64{mstatus_r_ena}} & mstatus)
					| ({64{mip_r_ena}} & mip)
					| ({64{mie_r_ena}} & mie)
					| ({64{mscratch_r_ena}} & mscratch);
assign	csr_r_data_unit = ({64{mcycle_r_ena_unit}} & mcycle)
					| ({64{mtvec_r_ena_unit}} & mtvec)
					| ({64{mepc_r_ena_unit}} & mepc)
					| ({64{mcause_r_ena_unit}} & mcause)
					| ({64{mstatus_r_ena_unit}} & mstatus)
					| ({64{mip_r_ena_unit}} & mip)
					| ({64{mie_r_ena_unit}} & mie)
					| ({64{mscratch_r_ena_unit}} & mscratch);					

endmodule








